package com.starmark.gateway.auth.security.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.starmark.gateway.auth.security.config.GatewayProjectConfig;
import com.starmark.gateway.auth.security.constants.GatewayConstant;
import com.starmark.gateway.auth.security.dto.GatewayAuthResourceDto;
import com.starmark.gateway.auth.security.dto.SecurityUserInfo;
import com.starmark.gateway.auth.security.service.IAuthService;
import com.starmark.gateway.auth.security.service.ICacheService;
import com.starmark.gateway.auth.security.utils.RequestHelper;
import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author starmark
 * @date 20-1-23  下午10:10
 */
@Service("authService")
public class AuthServiceImpl implements IAuthService {

    @Autowired
    private GatewayProjectConfig gatewayProjectConfig;
    @Autowired
    private ICacheService cacheService;

    @Override
    public Set<String> findRoleIdsByUserId(SecurityUserInfo securityUser) {
        return securityUser.getRoles();
    }

    @Override
    public List<String> findAuthResourceIdsByRoleId(String roleId, String projectCode) {
        String roleIds = cacheService.getCacheByKey(GatewayConstant.STARMARK_GATEWAY_RRR + projectCode + ":" + roleId);
        if (StrUtil.isEmpty(roleIds)) {
            return Collections.emptyList();
        }
        return JSONArray.parseArray(Objects.requireNonNull(JSONArray.parse(roleIds)).toString(), String.class);
    }

    public GatewayAuthResourceDto getAuthResource(String resourceId, String projectCode) {
        String authModel = cacheService.getCacheByKey(GatewayConstant.STARMARK_GATEWAY_RES + projectCode + ":" + resourceId);
        if (StrUtil.isEmpty(authModel)) {
            return null;
        }
        return JSON.parseObject(Objects.requireNonNull(JSON.parse(authModel)).toString(), GatewayAuthResourceDto.class);
    }


    @Override
    public boolean ignoreAuthentication(String url, String projectCode) {

        List<String> annoList = gatewayProjectConfig.getAnnoUrl();
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        return annoList.stream().anyMatch(annoUrl -> antPathMatcher.match(RequestHelper.handleEndUrl(annoUrl),url));
    }

    @Override
    public boolean hasPermission(SecurityUserInfo securityUser, String url, String method) {
        //如果是超管,直接返回
        if (securityUser.isAdmin()) {
            return true;
        }
        //判断该url是否纳入权限管理
        List<GatewayAuthResourceDto> resourceDtos=this.findAuthResourcesByProjectCode(securityUser.getProjectCode());
        if(CollectionUtils.isEmpty(resourceDtos)){
            return true;

        }

        boolean  authResult= resourceDtos.stream().anyMatch(resourceDto->hasPermissionAndResource(resourceDto,url,method,securityUser.getProjectCode()));
        // 纳入权限管理
        if(!authResult){
            return true;
        }
        Set<String> roleIds = this.findRoleIdsByUserId(securityUser);
        return roleIds.stream().anyMatch(roleId -> hasPermission(roleId, url, method, securityUser.getProjectCode()));
    }

    @Override
    public List<GatewayAuthResourceDto> findAuthResourcesByProjectCode(String projectCode) {
        Set<String> resourceRedisKeys=cacheService.getCacheKeysByKey(GatewayConstant.STARMARK_GATEWAY_RES + projectCode + ":*" );
        if(CollectionUtils.isEmpty(resourceRedisKeys)){
            return Collections.emptyList();
        }
        List<String> resourceStrs=cacheService.getCacheListByKeys(resourceRedisKeys);
        if(CollectionUtils.isEmpty(resourceStrs)){
            return Collections.emptyList();
        }
        return resourceStrs.parallelStream().map(resourceStr->JSON.parseObject(Objects.requireNonNull(JSON.parse(resourceStr)).toString(), GatewayAuthResourceDto.class)).collect(Collectors.toList());
    }

    private boolean hasPermission(String roleId, String url, String method, String projectCode) {
        List<String> resourceIds = this.findAuthResourceIdsByRoleId(roleId, projectCode);
        return resourceIds.stream().anyMatch(resourceId -> hasPermissionAndResourceId(resourceId, url, method, projectCode));


    }

    private boolean hasPermissionAndResource( GatewayAuthResourceDto resource, String url, String method, String projectCode) {
        if (resource == null) {
            return false;
        }
        if (StrUtil.isNotEmpty(resource.getMethodType())) {
            //允许方法的判断
            if (!method.equals(resource.getMethodType())) {
                return false;
            }
        }
        if(StrUtil.isEmpty(resource.getHref())){
            return false;
        }
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        return antPathMatcher.match(RequestHelper.handleEndUrl(resource.getHref()), url);
    }
    private boolean hasPermissionAndResourceId(String resourceId, String url, String method, String projectCode) {
        GatewayAuthResourceDto resource = this.getAuthResource(resourceId, projectCode);

        return this.hasPermissionAndResource(resource,url,method,projectCode);
    }

    public static void main(String[] args) {
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        System.out.println(antPathMatcher.match("/test/hr**", "/test/hr/overtime"));

    }


}
